/*
 * Copyright (c) 2013, SRI International
 * All rights reserved.
 * Licensed under the The BSD 3-Clause License;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 * 
 * http://opensource.org/licenses/BSD-3-Clause
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 * 
 * Redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution.
 * 
 * Neither the name of the aic-web-praise nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */
package com.sri.ai.lpitools.gwtgui.client.components.dialogs;

import java.util.ArrayList;
import java.util.List;

import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.cell.client.ValueUpdater;
import com.google.gwt.dom.client.Element;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.cellview.client.CellList;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.CaptionPanel;
import com.google.gwt.user.client.ui.DockLayoutPanel;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.LayoutPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.TextArea;
import com.google.gwt.view.client.SelectionChangeEvent;
import com.google.gwt.view.client.SingleSelectionModel;
import com.sri.ai.lpitools.cobra.gwtutil.dataobjects.shared.ModelInfo;
import com.sri.ai.lpitools.gwtgui.client.RPCServiceAsync;
import com.sri.ai.lpitools.gwtgui.client.components.manager.AICManager;
import com.sri.ai.lpitools.gwtgui.client.components.manager.ModelManager;
import com.sri.ai.lpitools.gwtgui.client.components.manager.UserManager;
import com.sri.ai.lpitools.gwtgui.client.util.JSONUtil;

/**
 * Dialog for selecting a model
 * @author bellwein
 */
public class SelectModelDialog extends CloseableDialogBox {

	private ModelManager modelManager;
	private UserManager userManager;
	private RPCServiceAsync rpc;
	private CaptionPanel listSelectPanel;
	
	//UI components
	private final SingleSelectionModel<String> selectionModel;
	private final CellList<String> modelList;
	private List<String> decriptions;

	public SelectModelDialog(ModelManager modelM, UserManager userM, RPCServiceAsync rpcService) {
		super();
		this.modelManager = modelM;
		this.userManager = userM;
		this.rpc = rpcService;
		setModal(true);
		setGlassEnabled(true);
		setAnimationEnabled(true);
		setHTML("Select Model");

		final Image image = new Image("images/loading_circle.gif");
		
		//don't edit the text cells
		EditTextCell clickIgnorer = new EditTextCell() {
			@Override
			public void onBrowserEvent(Context context, Element parent, String value,
					NativeEvent event, ValueUpdater<String> valueUpdater) {
				String type = event.getType();
				if ("click".equals(type)) {
					return;
				}
				super.onBrowserEvent(context, parent, value, event, valueUpdater);
			}
		};
		//build the dialog guts
		selectionModel = new SingleSelectionModel<String>();
		modelList = new CellList<String>(clickIgnorer);
		modelList.setSelectionModel(selectionModel);
		modelList.setEmptyListWidget(image);
		modelList.setRowCount(0, true);
		
		//create select button
		final Button selectButton = new Button("Select");
		selectButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				String selection = selectionModel.getSelectedObject();
				if (selection != null) {
					getModelFromRemote(selection);
					hide();
				}
			}
		});
		selectButton.setEnabled(false);
		
		Button cancelButton = new Button("Cancel");
		cancelButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				hide();
			}
		});
		
		final TextArea descriptionText = new TextArea();
		descriptionText.setReadOnly(true);
		descriptionText.setText("select a model");
		
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		// events based upon user selection
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
			
			@Override
			public void onSelectionChange(SelectionChangeEvent event) {
				String selection = selectionModel.getSelectedObject();
				if (selection != null) {
					selectButton.setEnabled(true);
					getDescription(selection);
					descriptionText.setText(getDescription(selection));
				} else {
					descriptionText.setText("select a model");
					selectButton.setEnabled(false);
				}
			}
		});

		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		//perform component layout
		//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
		SplitLayoutPanel splitLayoutPanel = new SplitLayoutPanel(5);
		LayoutPanel buttonPanel = new LayoutPanel();
		
		listSelectPanel = new CaptionPanel("Model");
		listSelectPanel.add(modelList);
		
		buttonPanel.add(selectButton);
		buttonPanel.add(cancelButton);
		buttonPanel.setWidgetLeftWidth(selectButton, 10, Unit.PCT, 35, Unit.PCT);
		buttonPanel.setWidgetRightWidth(cancelButton, 10, Unit.PCT, 35, Unit.PCT);
		
		DockLayoutPanel dockLayoutPanel = new DockLayoutPanel(Unit.PX);
		dockLayoutPanel.addSouth(buttonPanel, 24);
		dockLayoutPanel.add(descriptionText);
		
		splitLayoutPanel.addWest(listSelectPanel, 256);
		splitLayoutPanel.add(dockLayoutPanel);
		
		splitLayoutPanel.setSize("512px", "256px");
		add(splitLayoutPanel);
		
		//request the list of models from RPC
		rpc.getModelList(userManager.getCurrentUser().getUser(), new AsyncCallback<String>() {
			List<String> models = new ArrayList<String>();
			List<String> decriptions = new ArrayList<String>();
			@Override
			public void onSuccess(String result) {
				if (result == null) {
					MessageDialog.showMessageDialog("Null response for getModelList query");
					hide();
				}
				String modelListString = result;
				if(modelListString.startsWith("ERROR.")){
					models.add(modelListString);
				} else {
					List<ModelInfo> list = JSONUtil.getModelInfoList(modelListString);
					for(ModelInfo current: list){
						models.add(current.getModelTitle());
						decriptions.add(current.getModelTitle() + ":" + current.getShortDescription());
					}
//					models.addAll(JSONUtil.cleanJSONArray((JSONArray) jsv.get("models")));
				}
				setModels(models, decriptions);
			}
			
			@Override
			public void onFailure(Throwable caught) {
				MessageDialog.showMessageDialog(caught.getMessage());
				hide();
			}
		});
	}
	
	protected String getDescription(String modelTitle) {
		String descriptionString = "";
		for(String current: decriptions){
			if(current.startsWith(modelTitle+":")){
				String[] parts = current.split(":");
				descriptionString = parts[1];
				break;
			}
		}
		return descriptionString;
	}

	/**
	 * populate the list with models, replacing the UI components
	 * @param models
	 */
	public void setModels(List<String> models, List<String> decriptions) {		
		modelList.setRowData(models);
		this.decriptions = decriptions;
	}
	
	protected void getModelFromRemote(String modelName) {
		AICManager.openModel(modelName, userManager, modelManager);
	}
}
